﻿using DataDriven;
using DataService.Cache.Caching;
using DataService.Common;
using DataService.Core.Common;
using DataService.Core.DataHelper;
using DataService.Core.Log;
using DataService.Core.ServiceDTO;
using Dm;
using Dm.Config;
using MySqlX.XDevAPI.Relational;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Xml;

namespace DataService.DataAccessLayer
{
    /// <summary>
    /// 达梦数据库 数据库名、表名、字段名、索引名 建议都使用大写；
    /// 达梦不支持 一条命令执行多条语句
    /// </summary>
    public class DM : RemoteDB
    {
        private static int _exchangeLock = 0;
        protected override string ParameterPrefix => ":";
        public override DatabaseType DBType => DatabaseType.DaMeng;


        //达梦数据库的事务隔离级分为四级，默认是“读提交隔离级”。可以检查一下是否设置隔离级别为“只读事务”
        public override int Insert<T>(IList<T> dataList, string suffix, DbConnection conn, DbTransaction tran)
        {
            if (dataList == null || dataList.Count == 0)
                return 0;
            DmConnection dmConn = conn as DmConnection;
            DmTransaction sqlTran = null;
            if (tran != null)
            {
                sqlTran = tran as DmTransaction;
            }
            var dic = BatchHelper.ReturnBeatch<T>(dataList, 5000);
            try
            {
                InsertToDataBase<T>(suffix, dmConn, sqlTran, dic);
                return dataList.Count;
            }
            catch (Exception ex)
            {
                TraceLog.WriteLine($"{ex.StackTrace}，错误信息：{ex.Message}", $"{DBType}其它日志");
                throw ex;
            }


        }

        private void InsertToDataBase<T>(string stuff, DmConnection dmConn, DmTransaction dmTran, Dictionary<int, List<T>> dic)
        {
            string tableName = typeof(T).Name;
            var properties = typeof(T).GetProperties();
            using (DmBulkCopy bulkCopy = new DmBulkCopy(dmConn, DmBulkCopyOptions.Default, dmTran))
            {
                bulkCopy.BatchSize = 5000;
                bulkCopy.BulkCopyTimeout = 60;
                // 在插入的目标表
                bulkCopy.DestinationTableName = tableName + stuff;
                //DataTable列名与数据库列名的映射
                for (int i = 0; i < properties.Length; i++)
                {
                    bulkCopy.ColumnMappings.Add(properties[i].Name, properties[i].Name);
                }
                foreach (var item in dic)
                {
                    DataTable dataTable = DataTableHelper.ListToTable<T>(item.Value);
                    bulkCopy.WriteToServer(dataTable);
                }
            }
        }

        public override int BeatchInsert<T>(IList<T> dataList, string suffix, DbConnection conn, DbTransaction tran)
        {
            //达梦，不支持 多条语句；使用批量复制
            return Insert<T>(dataList, suffix, conn, tran);
        }


        public override bool CreateDataBaseSchema(string dbFileDir, string databaseName, DbConnection conn)
        {
            databaseName = databaseName.ToUpper();

            //datafile表空间存放的路径、size初始大小、maxsize最大大小、next每次扩展的大小；表空间初始大小为page的4096倍。不指定最大值，表示对空间不限制
            //达梦数据库一般默认是大小写敏感的；一般建议在使用达梦数据库时，命名一般都用大写
            //  建议单独给业务表空间划分磁盘
            //  建议数据表空间和索引表空间分开，减少IO争用。
            //在实际使用中，一般不建议使用单个巨大的数据文件，为一个表空间创建多个较小的数据文件是更好的选择
            //创建多个数据文件的表空间
            // create tablespace TEST datafile '/bigdata/DAMENG/TEST1.DBF' size 32 autoextend on next 2 maxsize 50,
            // '/bigdata/DAMENG/TEST2.DBF' size 32 autoextend on next 2 maxsize 50;

            //例 5 修改表空间 TS1 的数据文件 d:\TS1.dbf 自动扩展属性为每次扩展 10M，最大文件大小为 1G
            //ALTER TABLESPACE TS1 DATAFILE 'd:\TS1.dbf' AUTOEXTEND ON NEXT 10 MAXSIZE 1000;

            //理论上最多允许有 65535 个表空间，但用户允许创建的表空间 ID 取值范围为 0~32767，超过 32767 的只允许系统使用，ID 由系统自动分配，ID 不能重复使用，即使 删除掉已有表空间，也无法重复使用已用ID号，也就是说只要创建32768次表空间后，用 户将无法再创建表空间

            if (Interlocked.Exchange(ref _exchangeLock, 1) == 0)
            {
                string sql = "select count(1) from DBA_FREE_SPACE where TABLESPACE_NAME=:NAME;";
                Dictionary<string, object> dic = new Dictionary<string, object>();
                dic["NAME"] = databaseName;

                int count = MapperService.ScalarInternal<int>(conn, sql, dic, null, null, null, ParameterPrefix);
                if (count > 0)
                {
                    TraceLog.WriteLine($"【{DBType.ToString()}】{databaseName}已经存在", "创建架构");
                    return true;
                }
                //优化时定时任务提前把第二天的库、表创建完成
                //string tempDataBaseFilePath = @"D:\DataBaseBack";
                if (!Directory.Exists(dbFileDir))
                {
                    Directory.CreateDirectory(dbFileDir);
                }
                // 创建 TEST1 表空间，数据文件大小为 50M,开启自动扩展，每次扩展 1M，最大可扩展至 1G.

                //create tablespace "TEST1" datafile '/dm8/data/DAMENG/TEST101.DBF' size 50 autoextend on next 1 maxsize 1024 CACHE = NORMAL;
                // int maxSize = 1024 * 200;//最大为200G
                //此处不是很明白官方的交替使用的意思(暂时先用三个数据文件)，是写入一个事务数据写在1号数据文件，下个事务写在2号数据文件中？还是1号数据文件空间使用完毕后再使用2号数据文件？

                // string tableSpaceSql = $"CREATE TABLESPACE {databaseName} DATAFILE '{dbFileDir}\\{databaseName}_1.DBF' size 200 autoextend on next 100,'{dbFileDir}\\{databaseName}_2.DBF' size 200 autoextend on next 100,'{dbFileDir}\\{databaseName}_3.DBF' size 200 autoextend on next 100;";
                string tableSpaceSql = $"CREATE TABLESPACE {databaseName} DATAFILE '{dbFileDir}\\{databaseName}_1.DBF' size 200 autoextend on next 100,'{dbFileDir}\\{databaseName}_2.DBF' size 200 autoextend on next 100;";
                List<string> tableSchemaTexts = new List<string>();
                tableSchemaTexts.Add(tableSpaceSql);
                MapperService.ExecuteSchemaSql(conn, null, tableSchemaTexts, ParameterPrefix);
                TraceLog.WriteLine($"【{DBType.ToString()}】{dbFileDir}\\{databaseName}创建完成", "创建架构");
                Interlocked.Exchange(ref _exchangeLock, 0);
                return true;
            }
            else
            {
                TraceLog.WriteLine($"{dbFileDir}{databaseName}未进入线程创建数据库", "创建架构");
                return false;
            }
        }



        public override bool CreatTable(Tables tables, DbConnection conn, DbTransaction tran)
        {
            string dbTableSpace = tables.Columns[0].DataBaseName;

            //  //创建普通索引创建索引时可以指定索引的存储表空间，如果未指定，那么索引存放在用户的默认表空间下
            TraceLog.WriteLine($"数据库【{conn.Database}】，开始执行创建表结构脚本", $"{DBType}创建表");
            if (string.IsNullOrWhiteSpace(dbTableSpace))
            {
                dbTableSpace = GetLastTableSapce(conn, tran);
            }
            else
            {
                dbTableSpace = dbTableSpace.ToUpper();
            }
            #region 索引表空间；优化阶段，索引物理文件和业务数据物理文件需要分开
            //// string tableIndexSapce = $"{dbTableSpace}_Index";
            string tableIndexSapce = dbTableSpace;
            ////1.先创建索引表空间
            ////1.1 查询索引表空间 是否存在
            //string sql = $"select File_Name from dba_data_files where TableSpace_Name={ParameterPrefix}TableSpace_Name;";
            //Dictionary<string, object> dic = new Dictionary<string, object>();
            //dic["TableSpace_Name"] = dbTableSpace;
            //string tableSpaceFilePath = MapperService.ScalarInternal<string>(conn, sql, dic, null, null, null, ParameterPrefix);

            //string indexTableSapceFileDir = PathHelper.GetFileDirectoryName(tableSpaceFilePath);

            //CreateDataBaseSchema(indexTableSapceFileDir, tableIndexSapce, conn);
            #endregion



            //优化时定时任务提前把第二天的表创建完成
            List<ModelColumns> tableShemas = tables.Columns;
            List<ModelIndexs> tableIndexs = tables.Indexs;
            List<string> indexSqls = new List<string>();
            var tableSchemaTexts = CreateTableSql(tableShemas, tableIndexs, tableIndexSapce, dbTableSpace, ref indexSqls);
            string str = string.Join("*", tableSchemaTexts);
           TraceLog.WriteLine(str, "脚本", $"{DBType}创建表");
            //此处需要优化
            int count = MapperService.ExecuteSchemaSql(conn, tran, tableSchemaTexts, ParameterPrefix);
            if (count > 0)
            {
                List<string> tempTableNames = new List<string>();
                int hashCode = ConnectionString.GetHashCode();
                if (_tablesFields.ContainsKey(hashCode))
                {
                    tempTableNames = _tablesFields[hashCode];
                    if (!tempTableNames.Any(x => x == tableShemas[0].FullTableName))
                    {
                        tempTableNames.Add(tableShemas[0].FullTableName);
                        _tablesFields[hashCode] = tempTableNames;
                        TraceLog.WriteLine($"创建表结构【CreatTable】：{tableShemas[0].FullTableName}，添加到缓存", $"{DBType}创建表");
                    }
                }
                else
                {
                    tempTableNames.Add(tableShemas[0].FullTableName);
                    _tablesFields[hashCode] = tempTableNames;
                }
            }

            //添加索引
            if (indexSqls.Count > 0)
            {
                count = MapperService.ExecuteSchemaSql(conn, tran, indexSqls, ParameterPrefix);
            }



            return count > 0;
        }
        #region 创建架构
        private List<string> CreateTableSql(List<ModelColumns> tableSchemas, List<ModelIndexs> tableIndexs, string tableIndexSapce, string dbTableSpace, ref List<string> indexSqls)
        {
            List<string> textSchemas = new List<string>();
            var tableNameList = tableSchemas.Select(x => x.FullTableName).Distinct().ToList();
            foreach (var itemTableName in tableNameList)
            {
                var colSchemaList = tableSchemas.Where(x => x.FullTableName == itemTableName).ToList();
                StringBuilder stringBuilder = new StringBuilder();
                string tableName = itemTableName.ToUpper();//分表后缀,前调用分表前处理

                List<ModelIndexs> itemTableIndexs = tableIndexs.Where(x => x.FullTableName == itemTableName).ToList();
                //这里需要按照规则生成表名
                stringBuilder.AppendLine($"CREATE TABLE {tableName}(");

                foreach (var itemCol in colSchemaList)
                {
                    stringBuilder.Append(itemCol.ColName).Append(" ");
                    string itemColType = GetColType(itemCol).ToUpper();
                    stringBuilder.Append(itemColType).Append(" ");
                    stringBuilder.Append(GetColIsNull(itemCol)).Append(" ");
                    stringBuilder.AppendLine(DefaultValue(itemCol)).Append(",");
                }
                stringBuilder.Length--;
                stringBuilder.AppendLine($") storage (on \"{dbTableSpace}\");");
                textSchemas.Add(stringBuilder.ToString());
                //  dbTableSpace
                //一个表只有一个聚集索引，这里默认主键是聚集索引
                //创建约束、创建索引、组合索引、创建联合主键、创建自增字段、
                //创建索引前需要先删除该索引；DROP INDEX 表名.索引名[,…]
                //如果这个表没有主键，就需要查找是否有聚集索引
                //
                //with (drop_existing = on|off)，加上这个的意思是如果这个索引还在表上就drop 掉然后在create 一个新的。特别是在聚集索引上使用这个就可以不会引起非聚集索引的重建
                //UNIQUE 表示创建的索引具有唯一性
                //CLUSTERED 指明创建的索引为聚集索引
                //NONCLUSTERED 指明创建的索引为非聚集索引
                //ASC、DESC 指定特定的索引列的排序方式为升序(默认)或降序

                if (itemTableIndexs != null && itemTableIndexs.Count > 0)
                {
                    indexSqls = GetIndexScheme(itemTableIndexs, tableName, tableIndexSapce);
                }

            }

            return textSchemas;
        }

        protected override string GetColType(ModelColumns colDTO)
        {
            string tempColType = colDTO.ColType.ToLower();
            if (tempColType == "nvarchar" || tempColType == "varchar" || tempColType == "char" || tempColType == "nchar")
            {
                int tempLength = colDTO.ValueLength;
                if (tempLength == -1)
                {
                    return $"{tempColType}(max)";
                }
                return $"{tempColType}({tempLength})";
            }
            else if (tempColType == "binary" || tempColType == "varbinary")
            {
                int tempLength = colDTO.ValueLength;
                if (tempLength == -1)
                {
                    return $"{tempColType}(max)";
                }
                return $"{tempColType}({tempLength})";
            }
            else if (tempColType == "bit" || tempColType == "tinyint" || tempColType == "smallint" || tempColType == "int" || tempColType == "bigint")
            {
                return tempColType;
            }
            else if (tempColType == "text" || tempColType == "blob" || tempColType == "clob" || tempColType == "image")
            {
                return tempColType;
            }
            else if (tempColType == "uniqueidentifier")
            {
                return "VARCHAR(36)";
            }
            else if (tempColType == "date" || tempColType == "time")
            {
                return tempColType;
            }
            else if (tempColType == "datetime" || tempColType == "smalldatetime" || tempColType == "timestamp")
            {
                //如果报错换成 "DATETIME"
                return "TIMESTAMP";
            }
            else if (tempColType == "smallmoney" || tempColType == "money")
            {
                return "real";
            }
            else if (tempColType == "float")
            {
                return "FLOAT";
            }
            else if (tempColType == "double")
            {
                return "DOUBLE";
            }
            else if (tempColType == "decimal")
            {
                int tempLength = colDTO.ValueLength;
                int num = colDTO.ScaleLength;
                //如果DEC报错 换成 NUMERIC({tempLength},{num})或者decimal({tempLength},{num})
                return $"DEC({tempLength},{num})";
            }
            else if (tempColType == "numeric")
            {
                int tempLength = colDTO.ValueLength;
                int num = colDTO.ScaleLength;
                return $"NUMERIC({tempLength},{num})";
            }
            else
            {
                return tempColType;
            }
        }
        private string GetColIsNull(ModelColumns colDTO)
        {
            return colDTO.IsNullable ? "NULL" : "NOT NULL";
        }
        private string DefaultValue(ModelColumns colDTO)
        {
            if (string.IsNullOrEmpty(colDTO.DefaultValue))
            {
                return "";
            }
            return $"default {colDTO.DefaultValue}";
        }

        private List<string> GetIndexScheme(List<ModelIndexs> itemTableIndexs, string itemTableName, string tableSpace)
        {
            //  因此，DM 提供三种方式供用户指定聚集索引键：
            //            CLUSTER PRIMARY KEY：指定列为聚集索引键，并同时指定为主键，称为聚集主键；
            //CLUSTER INDEX：指定列为聚集索引键，但是是非唯一的；
            //CLUSTER UNIQUE INDEX：指定列为聚集索引键，并且是唯一的。
            // CREATE INDEX 语句中列的排序会影响查询的性能

            //创建聚集索引，索引键为ID。
            //  CREATE CLUSTER INDEX C1 on T1(ID);
            //创建非聚集索引，索引键为NAME。
            // CREATE INDEX S1 on T1(NAME);
            List<string> sqls = new List<string>();
            var indexNames = itemTableIndexs.Select(x => x.IndexName).Distinct().ToList();
            int index = 0;
            foreach (string itemIndexName in indexNames)
            {
                index++;
                var tempIndexs = itemTableIndexs.Where(x => x.IndexName == itemIndexName).ToList();
                string colNames = string.Join(",", tempIndexs.Select(x => x.ColumnName));
                var itemTableIndexsDTO = tempIndexs.FirstOrDefault();
                //达梦数据库，每一个表有且只有一个聚集索引,每一个表可以有多个非聚集索引
                //string tempIndexName = itemIndexName;
                //这里认为主键是聚集索引，正常逻辑，主键也应该是聚集索引
                if (itemTableIndexsDTO.PrimaryKey)
                {
                    //在建立聚集索引的时候在多个字段上建立聚集索引是没有任何意义的；因为聚集索引查找是根据建立索引的第一个字段来查找
                    //string pkIndex = $"ALTER TABLE {itemTableName} ADD CONSTRAINT {item.IndexName} PRIMARY KEY CLUSTERED({item.ColumnName} {item.Sort}); ";
                    // string pkIndexSql = $"ALTER TABLE {itemTableName} ADD CONSTRAINT {itemTableIndexsDTO.IndexName} PRIMARY KEY({colNames} {itemTableIndexsDTO.Sort}); ";


                    //ALTER TABLE T1 ADD CONSTRAINT PK_EMP_NAME PRIMARY KEY (C1);


                    string tempIndexName = $"PK_{itemTableName}_{index}";
                    string pkIndexSql = $"ALTER TABLE {itemTableName} add CLUSTER PRIMARY KEY({colNames});";
                    sqls.Add(pkIndexSql);
                }
                else if (!itemTableIndexsDTO.PrimaryKey && itemTableIndexsDTO.Type_Desc == "CLUSTERED")
                {
                    string tempIndexName = $"CLUSTERED_INDEX_{itemTableName}_{index}";
                    //CREATE CLUSTER INDEX C1 on T1(ID);
                    //非主键的聚集索引

                    string tempSql = $" CREATE CLUSTER INDEX {tempIndexName} ON {itemTableName}({colNames}) TABLESPACE \"{tableSpace}\";";
                    sqls.Add(tempSql);
                }
                else if (itemTableIndexsDTO.UQIQUE && !itemTableIndexsDTO.PrimaryKey)
                {
                    //CREATE UNIQUE INDEX dept_unique_index ON dept(dname) STORAGE(ON users);
                    string tempIndexName = $"UNIQUE_INDEX_{itemTableName}_{index}";
                    //string tempSql="CREATE UNIQUE NONCLUSTERED INDEX sno_cl_ind ON TestIndexTable(sfzUniqueIndex_2);"
                    string tempSql = $" CREATE UNIQUE INDEX {tempIndexName} ON {itemTableName}({colNames}) TABLESPACE \"{tableSpace}\";";
                    sqls.Add(tempSql);
                }
                else
                {
                    string tempIndexName = $"INDEX_{itemTableName}_{index}";
                    string tempSql = $" CREATE INDEX {tempIndexName} ON {itemTableName}({colNames}) TABLESPACE \"{tableSpace}\"; ";
                    sqls.Add(tempSql);
                }
            }
            return sqls;
        }
        #endregion

        #region 查询达梦参数

        protected override string SetTotalRowsSql(string tableName, string dataBaseName, string schema)
        {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.AppendLine("begin");
            string sql = $"DBMS_STATS.GATHER_TABLE_STATS('{schema}','{tableName}');"; //更新表
            stringBuilder.AppendLine(sql);
            stringBuilder.AppendLine($"select convert(int,NUM_ROWS) as NUM_ROWS from User_Tables where TABLE_NAME='{tableName}';");
            stringBuilder.Append("end;");
            return stringBuilder.ToString();

        }
        public override List<string> FindAllTableNames(DbConnection conn, DbTransaction tran)
        {
            string sql = "select TABLE_NAME from User_Tables";
            //string sql = "select NAME from v$tablespace where Name!='SYSTEM' and Name!='ROLL' and Name!='TEMP' and Name!='MAIN' order by Id desc;";
            var list = MapperService.QueryInternal<string>(conn, sql, null, tran, null, null, ParameterPrefix).ToList();
            return list;
        }

        private string GetDMInstance(DbConnection conn, DbTransaction tran)
        {
            //  string sql = "select * inst_name from v$instance;";//查询实例信息
            string sql = "select NAME inst_name from v$instance;";//查询实例名称
            return MapperService.ScalarInternal<string>(conn, sql, null, tran, null, CommandType.Text, ParameterPrefix);
        }
        private string GetLastTableSapce(DbConnection conn, DbTransaction tran)
        {
            string sql = "select top 1 NAME from v$tablespace where Name!='SYSTEM' and Name!='ROLL' and Name!='TEMP' and Name!='MAIN' order by Id desc;";
            return MapperService.ScalarInternal<string>(conn, sql, null, tran, null, CommandType.Text, ParameterPrefix);
        }
        /// <summary>
        /// 根据表名查询所属模式名
        /// </summary>
        private string GetOwner(string tableName,DbConnection conn, DbTransaction tran)
        {
            string sql = $"select OWNER from all_Tables where TABLE_NAME={ParameterPrefix}TableName;";
            Dictionary<string, object> dic = new Dictionary<string, object>();
            dic["TableName"] = tableName;
            return MapperService.ScalarInternal<string>(conn, sql, dic, tran, null, CommandType.Text, ParameterPrefix);
        }
        /// <summary>
        /// 更新统计信息
        /// </summary>
        /// <returns></returns>
        private void Upgrade()
        {
            //更新统计信息（模式T11下的所有对象）
            // DBMS_STATS.GATHER_SCHEMA_stats('T11')
            //更新统计信息（模式T11下的表T11）
            // DBMS_STATS.GATHER_TABLE_STATS('T11', 'T11');
            //更新统计信息（模式T11下的索引IDX_T11_ID）
            // DBMS_STATS.GATHER_INDEX_STATS('T11', 'IDX_T11_ID');
        }
        ///// <summary>
        ///// 获取字段信息
        ///// </summary>
        ///// <param name="conn"></param>
        ///// <param name="tran"></param>
        ///// <returns></returns>
        //private string GetTableColumns(DbConnection conn, DbTransaction tran)
        //{
        //    string sql = " select* from all_tab_columns where owner='SYSDBA';";
        //    return MapperService.ScalarInternal<string>(conn, sql, null, tran, null, CommandType.Text);
        //}
        protected override string GetFullName(string fullTableName)
        {
            return fullTableName.ToUpper();
        }
        public override string GetIsExistsTableSql(string databaseName, string schemaName)
        {
            // string sql = $"select Count(1) from all_Tables where TABLE_NAME={ParameterPrefix}Name";
            string sql = $"select Count(1) from dba_tables where TABLE_NAME={ParameterPrefix}Name";
            return sql;
        }
        #endregion

        ////使用索引idx1查询
        //explain select * from t1 where c2 = 130;  //当数据量很大时
        //explain select * from t1 index idx1 where c2 = 130;  //或直接指定全局索引


        #region 查询达梦 表、字段 结构
        private String ColumnSchemaSql
        {

            get
            {
                string sql = @"select tm.TABLE_NAME as TableName,tm.COLUMN_NAME as ColName,
(select Convert(Bit,count(1)) from  SYS.SYSCOLUMNS a,all_tables b,sys.sysobjects c where a.INFO2 & 0x01 = 0x01
and a.id=c.id and c.name= b.table_name and b.table_name=tm.TABLE_Name and a.name=tm.COLUMN_NAME) as Flag,
(SELECT Convert(Bit,count(1)) FROM ALL_CONSTRAINTS as a inner join all_CONS_COLUMNS as b on a.OWNER=b.OWNER and a.TABLE_NAME=b.TABLE_NAME
where a.CONSTRAINT_TYPE='P' and b.TABLE_NAME=tm.TABLE_Name and b.COLUMN_NAME=tm.COLUMN_NAME) as IsPK,
tm.DATA_TYPE as ColType,
(case when tm.DATA_PRECISION is null then convert(int,tm.CHAR_LENGTH) else convert(int,tm.DATA_PRECISION) end) as ValueLength, 
convert(int,tm.DATA_LENGTH) as ColLength,
convert(int,tm.DATA_SCALE) as ScaleLength,
(case when tm.NULLABLE='Y' then Convert(Bit,1) else Convert(Bit,0) end) as IsNullable,
 tm.DATA_DEFAULT as DefaultValue
 from all_tab_columns as tm";
                return sql;
            }

        }

        private string IndexSql
        {
            get
            {
                string sql = @"select 
in1.TABLE_NAME as TableName,
in1.INDEX_NAME as IndexName,
in1.COLUMN_NAME as ColumnName,
 (SELECT Convert(Bit,count(1)) FROM ALL_CONSTRAINTS as a inner join all_CONS_COLUMNS as b on a.OWNER=b.OWNER and a.TABLE_NAME=b.TABLE_NAME
where a.CONSTRAINT_TYPE='P' and b.TABLE_NAME=in1.TABLE_NAME and b.COLUMN_NAME=in1.COLUMN_NAME) as PrimaryKey,
ai.INDEX_TYPE as Type_Desc,
(case when ai.UNIQUENESS='UNIQUE' then Convert(Bit,1) else Convert(Bit,0) end) as UQIQUE
 from DBA_IND_COLUMNS as in1 inner join  ALL_INDEXES as ai on ai.INDEX_NAME=in1.INDEX_NAME and ai.OWNER=in1.INDEX_OWNER";
                return sql;
            }
        }




        public override Tables FindAllModelTableSchema(List<string> tableNames, DbConnection conn)
        {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.AppendLine(ColumnSchemaSql);
            Dictionary<string, object> dic = new Dictionary<string, object>();
            stringBuilder.Append(" WHERE tm.TABLE_NAME IN(");
            for (int i = 0; i < tableNames.Count; i++)
            {
                stringBuilder.Append($"{ParameterPrefix}name{i}").Append(",");
                dic[$"name{i}"] = tableNames[i].ToUpper();
            }
            stringBuilder.Length--;
            stringBuilder.Append(")");


            StringBuilder indexBuilder = new StringBuilder();
            indexBuilder.AppendLine(IndexSql);
            Dictionary<string, object> indexDic = new Dictionary<string, object>();
            indexBuilder.Append(" WHERE in1.TABLE_NAME IN(");
            for (int i = 0; i < tableNames.Count; i++)
            {
                indexBuilder.Append($"{ParameterPrefix}name{i}").Append(",");
                indexDic[$"name{i}"] = tableNames[i].ToUpper();
            }
            indexBuilder.Length--;
            indexBuilder.Append(")");

            List<ModelColumns> dmColumns = MapperService.QueryInternal<ModelColumns>(conn, stringBuilder.ToString(), dic, null, null, null, ParameterPrefix).ToList();
            List<ModelColumns> modelModelColumns = GetSourceModelColumns();
            modelModelColumns = modelModelColumns.Where(x => tableNames.Any(t => t.ToUpper() == x.TableName.ToUpper())).ToList() ?? new List<ModelColumns>();
            //达梦 Identity 是个关键字，这里赋值
            foreach (var item in dmColumns)
            {
                item.Identity = item.Flag;
                string tempTableName = item.TableName.ToUpper();
                string tempColumn = item.ColName.ToUpper();
                var tempModelColumns = modelModelColumns.Find(x => x.TableName.ToUpper() == tempTableName && x.ColName.ToUpper() == tempColumn) ?? new ModelColumns();
                item.FieldDes = tempModelColumns.FieldDes;
            }
            List<ModelIndexs> indexs = MapperService.QueryInternal<ModelIndexs>(conn, indexBuilder.ToString(), indexDic, null, null, null, ParameterPrefix).ToList() ?? new List<ModelIndexs>();
            Tables tables = new Tables()
            {
                Columns = dmColumns,
                Indexs = indexs
            };
            return tables;
        }

        public override List<ModelColumns> FindAllColumns(DbConnection conn)
        {
            List<ModelColumns> columns = MapperService.QueryInternal<ModelColumns>(conn, ColumnSchemaSql, null, null, null, null, ParameterPrefix).ToList();
            return columns;
        }
        public override List<ModelIndexs> FindAllIndexs(DbConnection conn)
        {
            List<ModelIndexs> indexs = MapperService.QueryInternal<ModelIndexs>(conn, IndexSql, null, null, null, null, ParameterPrefix).ToList() ?? new List<ModelIndexs>();
            return indexs;
        }
        #endregion

    }
}
